{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"school_cell_uuid": "6b664ac5e2c6492aa0e3f5cbd9bd25cf"
},
"source": [
"# 4.6 데이터프레임 합성"
]
},
{
"cell_type": "markdown",
"metadata": {
"school_cell_uuid": "4d3579de59f54ae6af27431a03eb32cd"
},
"source": [
"판다스는 두 개 이상의 데이터프레임을 하나로 합치는 데이터 병합(merge)이나 연결(concatenate)을 지원한다."
]
},
{
"cell_type": "markdown",
"metadata": {
"school_cell_uuid": "b41585414225461aa48873974dab9ff4"
},
"source": [
"## `merge` 함수를 사용한 데이터프레임 병합"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"```{margin}\n",
"`merge`\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {
"school_cell_uuid": "c61603512a064b10b418508bd086c467"
},
"source": [
"`merge` 함수는 두 데이터 프레임의 공통 열 혹은 인덱스를 기준으로 두 개의 테이블을 합친다. 이 때 기준이 되는 열, 행의 데이터를 키(key)라고 한다."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"school_cell_uuid": "ca995b1dc8314531802808260235aa48"
},
"outputs": [
{
"data": {
"text/html": [
"
\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" 고객번호 | \n",
" 이름 | \n",
"
\n",
" \n",
" \n",
" \n",
" 0 | \n",
" 1001 | \n",
" 둘리 | \n",
"
\n",
" \n",
" 1 | \n",
" 1002 | \n",
" 도우너 | \n",
"
\n",
" \n",
" 2 | \n",
" 1003 | \n",
" 또치 | \n",
"
\n",
" \n",
" 3 | \n",
" 1004 | \n",
" 길동 | \n",
"
\n",
" \n",
" 4 | \n",
" 1005 | \n",
" 희동 | \n",
"
\n",
" \n",
" 5 | \n",
" 1006 | \n",
" 마이콜 | \n",
"
\n",
" \n",
" 6 | \n",
" 1007 | \n",
" 영희 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" 고객번호 이름\n",
"0 1001 둘리\n",
"1 1002 도우너\n",
"2 1003 또치\n",
"3 1004 길동\n",
"4 1005 희동\n",
"5 1006 마이콜\n",
"6 1007 영희"
]
},
"execution_count": 1,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df1 = pd.DataFrame({\n",
" '고객번호': [1001, 1002, 1003, 1004, 1005, 1006, 1007],\n",
" '이름': ['둘리', '도우너', '또치', '길동', '희동', '마이콜', '영희']\n",
"}, columns=['고객번호', '이름'])\n",
"df1"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"school_cell_uuid": "7b868901382c4405954d1c67d34b8eb8"
},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" 고객번호 | \n",
" 금액 | \n",
"
\n",
" \n",
" \n",
" \n",
" 0 | \n",
" 1001 | \n",
" 10000 | \n",
"
\n",
" \n",
" 1 | \n",
" 1001 | \n",
" 20000 | \n",
"
\n",
" \n",
" 2 | \n",
" 1005 | \n",
" 15000 | \n",
"
\n",
" \n",
" 3 | \n",
" 1006 | \n",
" 5000 | \n",
"
\n",
" \n",
" 4 | \n",
" 1008 | \n",
" 100000 | \n",
"
\n",
" \n",
" 5 | \n",
" 1001 | \n",
" 30000 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" 고객번호 금액\n",
"0 1001 10000\n",
"1 1001 20000\n",
"2 1005 15000\n",
"3 1006 5000\n",
"4 1008 100000\n",
"5 1001 30000"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df2 = pd.DataFrame({\n",
" '고객번호': [1001, 1001, 1005, 1006, 1008, 1001],\n",
" '금액': [10000, 20000, 15000, 5000, 100000, 30000]\n",
"}, columns=['고객번호', '금액'])\n",
"df2"
]
},
{
"cell_type": "markdown",
"metadata": {
"school_cell_uuid": "433dd514e3484b7b99ac1f0d5602cb56"
},
"source": [
"`merge` 함수로 위의 두 데이터프레임 df1, df2 를 합치면 공통 열인 `고객번호` 열을 기준으로 데이터를 찾아서 합친다. 이 때 기본적으로는 양쪽 데이터프레임에 모두 키가 존재하는 데이터만 보여주는 inner join 방식을 사용한다."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"school_cell_uuid": "65b0323d90f0430e9edd8ea43529cb03"
},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" 고객번호 | \n",
" 이름 | \n",
" 금액 | \n",
"
\n",
" \n",
" \n",
" \n",
" 0 | \n",
" 1001 | \n",
" 둘리 | \n",
" 10000 | \n",
"
\n",
" \n",
" 1 | \n",
" 1001 | \n",
" 둘리 | \n",
" 20000 | \n",
"
\n",
" \n",
" 2 | \n",
" 1001 | \n",
" 둘리 | \n",
" 30000 | \n",
"
\n",
" \n",
" 3 | \n",
" 1005 | \n",
" 희동 | \n",
" 15000 | \n",
"
\n",
" \n",
" 4 | \n",
" 1006 | \n",
" 마이콜 | \n",
" 5000 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" 고객번호 이름 금액\n",
"0 1001 둘리 10000\n",
"1 1001 둘리 20000\n",
"2 1001 둘리 30000\n",
"3 1005 희동 15000\n",
"4 1006 마이콜 5000"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"pd.merge(df1, df2)"
]
},
{
"cell_type": "markdown",
"metadata": {
"school_cell_uuid": "9fffca783ba54a7e9df1a7f776e5ff4a"
},
"source": [
"outer join 방식은 키 값이 한쪽에만 있어도 데이터를 보여준다."
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"school_cell_uuid": "a5e9de8a231f47629d7847a48f9d59a9"
},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" 고객번호 | \n",
" 이름 | \n",
" 금액 | \n",
"
\n",
" \n",
" \n",
" \n",
" 0 | \n",
" 1001 | \n",
" 둘리 | \n",
" 10000.0 | \n",
"
\n",
" \n",
" 1 | \n",
" 1001 | \n",
" 둘리 | \n",
" 20000.0 | \n",
"
\n",
" \n",
" 2 | \n",
" 1001 | \n",
" 둘리 | \n",
" 30000.0 | \n",
"
\n",
" \n",
" 3 | \n",
" 1002 | \n",
" 도우너 | \n",
" NaN | \n",
"
\n",
" \n",
" 4 | \n",
" 1003 | \n",
" 또치 | \n",
" NaN | \n",
"
\n",
" \n",
" 5 | \n",
" 1004 | \n",
" 길동 | \n",
" NaN | \n",
"
\n",
" \n",
" 6 | \n",
" 1005 | \n",
" 희동 | \n",
" 15000.0 | \n",
"
\n",
" \n",
" 7 | \n",
" 1006 | \n",
" 마이콜 | \n",
" 5000.0 | \n",
"
\n",
" \n",
" 8 | \n",
" 1007 | \n",
" 영희 | \n",
" NaN | \n",
"
\n",
" \n",
" 9 | \n",
" 1008 | \n",
" NaN | \n",
" 100000.0 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" 고객번호 이름 금액\n",
"0 1001 둘리 10000.0\n",
"1 1001 둘리 20000.0\n",
"2 1001 둘리 30000.0\n",
"3 1002 도우너 NaN\n",
"4 1003 또치 NaN\n",
"5 1004 길동 NaN\n",
"6 1005 희동 15000.0\n",
"7 1006 마이콜 5000.0\n",
"8 1007 영희 NaN\n",
"9 1008 NaN 100000.0"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"pd.merge(df1, df2, how='outer')"
]
},
{
"cell_type": "markdown",
"metadata": {
"school_cell_uuid": "8561fb8d59014b65b53338fa62e2cf5b"
},
"source": [
"left, right 방식은 각각 첫번째, 혹은 두번째 데이터프레임의 키 값을 모두 보여준다."
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"school_cell_uuid": "57296be296e74e20a3af293684c7b5e6"
},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" 고객번호 | \n",
" 이름 | \n",
" 금액 | \n",
"
\n",
" \n",
" \n",
" \n",
" 0 | \n",
" 1001 | \n",
" 둘리 | \n",
" 10000.0 | \n",
"
\n",
" \n",
" 1 | \n",
" 1001 | \n",
" 둘리 | \n",
" 20000.0 | \n",
"
\n",
" \n",
" 2 | \n",
" 1001 | \n",
" 둘리 | \n",
" 30000.0 | \n",
"
\n",
" \n",
" 3 | \n",
" 1002 | \n",
" 도우너 | \n",
" NaN | \n",
"
\n",
" \n",
" 4 | \n",
" 1003 | \n",
" 또치 | \n",
" NaN | \n",
"
\n",
" \n",
" 5 | \n",
" 1004 | \n",
" 길동 | \n",
" NaN | \n",
"
\n",
" \n",
" 6 | \n",
" 1005 | \n",
" 희동 | \n",
" 15000.0 | \n",
"
\n",
" \n",
" 7 | \n",
" 1006 | \n",
" 마이콜 | \n",
" 5000.0 | \n",
"
\n",
" \n",
" 8 | \n",
" 1007 | \n",
" 영희 | \n",
" NaN | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" 고객번호 이름 금액\n",
"0 1001 둘리 10000.0\n",
"1 1001 둘리 20000.0\n",
"2 1001 둘리 30000.0\n",
"3 1002 도우너 NaN\n",
"4 1003 또치 NaN\n",
"5 1004 길동 NaN\n",
"6 1005 희동 15000.0\n",
"7 1006 마이콜 5000.0\n",
"8 1007 영희 NaN"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"pd.merge(df1, df2, how='left')"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"school_cell_uuid": "767dee654c874038baf59e4f7cb3b51f"
},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" 고객번호 | \n",
" 이름 | \n",
" 금액 | \n",
"
\n",
" \n",
" \n",
" \n",
" 0 | \n",
" 1001 | \n",
" 둘리 | \n",
" 10000 | \n",
"
\n",
" \n",
" 1 | \n",
" 1001 | \n",
" 둘리 | \n",
" 20000 | \n",
"
\n",
" \n",
" 2 | \n",
" 1001 | \n",
" 둘리 | \n",
" 30000 | \n",
"
\n",
" \n",
" 3 | \n",
" 1005 | \n",
" 희동 | \n",
" 15000 | \n",
"
\n",
" \n",
" 4 | \n",
" 1006 | \n",
" 마이콜 | \n",
" 5000 | \n",
"
\n",
" \n",
" 5 | \n",
" 1008 | \n",
" NaN | \n",
" 100000 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" 고객번호 이름 금액\n",
"0 1001 둘리 10000\n",
"1 1001 둘리 20000\n",
"2 1001 둘리 30000\n",
"3 1005 희동 15000\n",
"4 1006 마이콜 5000\n",
"5 1008 NaN 100000"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"pd.merge(df1, df2, how='right')"
]
},
{
"cell_type": "markdown",
"metadata": {
"school_cell_uuid": "38c341b4e3704053b8ee2046ebd9dbb9"
},
"source": [
"만약 테이블에 키 값이 같은 데이터가 여러개 있는 경우에는 있을 수 있는 모든 경우의 수를 따져서 조합을 만들어 낸다."
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"school_cell_uuid": "6abf0c3733604366bc45c319cbedc72b"
},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" 품종 | \n",
" 꽃잎길이 | \n",
"
\n",
" \n",
" \n",
" \n",
" 0 | \n",
" setosa | \n",
" 1.4 | \n",
"
\n",
" \n",
" 1 | \n",
" setosa | \n",
" 1.3 | \n",
"
\n",
" \n",
" 2 | \n",
" virginica | \n",
" 1.5 | \n",
"
\n",
" \n",
" 3 | \n",
" virginica | \n",
" 1.3 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" 품종 꽃잎길이\n",
"0 setosa 1.4\n",
"1 setosa 1.3\n",
"2 virginica 1.5\n",
"3 virginica 1.3"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df1 = pd.DataFrame({\n",
" '품종': ['setosa', 'setosa', 'virginica', 'virginica'],\n",
" '꽃잎길이': [1.4, 1.3, 1.5, 1.3]},\n",
" columns=['품종', '꽃잎길이'])\n",
"df1"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"school_cell_uuid": "c93741632f264ff2bc19857e19f8288c"
},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" 품종 | \n",
" 꽃잎너비 | \n",
"
\n",
" \n",
" \n",
" \n",
" 0 | \n",
" setosa | \n",
" 0.4 | \n",
"
\n",
" \n",
" 1 | \n",
" virginica | \n",
" 0.3 | \n",
"
\n",
" \n",
" 2 | \n",
" virginica | \n",
" 0.5 | \n",
"
\n",
" \n",
" 3 | \n",
" versicolor | \n",
" 0.3 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" 품종 꽃잎너비\n",
"0 setosa 0.4\n",
"1 virginica 0.3\n",
"2 virginica 0.5\n",
"3 versicolor 0.3"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df2 = pd.DataFrame({\n",
" '품종': ['setosa', 'virginica', 'virginica', 'versicolor'],\n",
" '꽃잎너비': [0.4, 0.3, 0.5, 0.3]},\n",
" columns=['품종', '꽃잎너비'])\n",
"df2"
]
},
{
"cell_type": "markdown",
"metadata": {
"school_cell_uuid": "5eb8af9497764b56b13cf9c67c24db18"
},
"source": [
"이 데이터에서 키 값 setosa에 대해 왼쪽 데이터프레임는 1.4와 1.3라는 2개의 데이터, 오른쪽 데이터프레임에 0.4라는 1개의 데이터가 있으므로 병합된 데이터에는 setosa가 (1.4, 0.4), (1.3, 0.4) 두 개의 데이터가 생긴다. 키 값 virginica의 경우에는 왼쪽 데이터프레임에 1.5와 1.3라는 2개의 데이터, 오른쪽 데이터프레임에 0.3와 0.5라는 2개의 데이터가 있으므로 2개와 2개의 조합에 의해 4가지 값이 생긴다."
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {
"school_cell_uuid": "5e21b76a347d476eac374283a316f269"
},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" 품종 | \n",
" 꽃잎길이 | \n",
" 꽃잎너비 | \n",
"
\n",
" \n",
" \n",
" \n",
" 0 | \n",
" setosa | \n",
" 1.4 | \n",
" 0.4 | \n",
"
\n",
" \n",
" 1 | \n",
" setosa | \n",
" 1.3 | \n",
" 0.4 | \n",
"
\n",
" \n",
" 2 | \n",
" virginica | \n",
" 1.5 | \n",
" 0.3 | \n",
"
\n",
" \n",
" 3 | \n",
" virginica | \n",
" 1.5 | \n",
" 0.5 | \n",
"
\n",
" \n",
" 4 | \n",
" virginica | \n",
" 1.3 | \n",
" 0.3 | \n",
"
\n",
" \n",
" 5 | \n",
" virginica | \n",
" 1.3 | \n",
" 0.5 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" 품종 꽃잎길이 꽃잎너비\n",
"0 setosa 1.4 0.4\n",
"1 setosa 1.3 0.4\n",
"2 virginica 1.5 0.3\n",
"3 virginica 1.5 0.5\n",
"4 virginica 1.3 0.3\n",
"5 virginica 1.3 0.5"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"pd.merge(df1, df2)"
]
},
{
"cell_type": "markdown",
"metadata": {
"school_cell_uuid": "9e429e26659a4d0b85b8143d0709b5c2"
},
"source": [
"두 데이터프레임에서 이름이 같은 열은 모두 키가 된다. 만약 이름이 같아도 키가 되면 안되는 열이 있다면 `on` 인수로 기준열을 명시해야 한다. 다음 예에서 첫번째 데이터프레임의 \"데이터\"는 실제로는 금액을 나타내는 데이터이고 두번째 데이터프레임의 \"데이터\"는 실제로는 성별을 나타내는 데이터이므로 이름이 같아도 다른 데이터이다. 따라서 이 열은 기준열이 되면 안된다."
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {
"school_cell_uuid": "17670124b837436eaf758ee469a2afe9"
},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" 고객명 | \n",
" 날짜 | \n",
" 데이터 | \n",
"
\n",
" \n",
" \n",
" \n",
" 0 | \n",
" 춘향 | \n",
" 2018-01-01 | \n",
" 20000 | \n",
"
\n",
" \n",
" 1 | \n",
" 춘향 | \n",
" 2018-01-02 | \n",
" 30000 | \n",
"
\n",
" \n",
" 2 | \n",
" 몽룡 | \n",
" 2018-01-01 | \n",
" 100000 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" 고객명 날짜 데이터\n",
"0 춘향 2018-01-01 20000\n",
"1 춘향 2018-01-02 30000\n",
"2 몽룡 2018-01-01 100000"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df1 = pd.DataFrame({\n",
" '고객명': ['춘향', '춘향', '몽룡'],\n",
" '날짜': ['2018-01-01', '2018-01-02', '2018-01-01'],\n",
" '데이터': ['20000', '30000', '100000']})\n",
"df1"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {
"school_cell_uuid": "8cbde58855f94f9c98c83a2240c6d9d4"
},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" 고객명 | \n",
" 데이터 | \n",
"
\n",
" \n",
" \n",
" \n",
" 0 | \n",
" 춘향 | \n",
" 여자 | \n",
"
\n",
" \n",
" 1 | \n",
" 몽룡 | \n",
" 남자 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" 고객명 데이터\n",
"0 춘향 여자\n",
"1 몽룡 남자"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df2 = pd.DataFrame({\n",
" '고객명': ['춘향', '몽룡'],\n",
" '데이터': ['여자', '남자']})\n",
"df2"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {
"school_cell_uuid": "4084064009d04ac2addb64ef89cb3310"
},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" 고객명 | \n",
" 날짜 | \n",
" 데이터_x | \n",
" 데이터_y | \n",
"
\n",
" \n",
" \n",
" \n",
" 0 | \n",
" 춘향 | \n",
" 2018-01-01 | \n",
" 20000 | \n",
" 여자 | \n",
"
\n",
" \n",
" 1 | \n",
" 춘향 | \n",
" 2018-01-02 | \n",
" 30000 | \n",
" 여자 | \n",
"
\n",
" \n",
" 2 | \n",
" 몽룡 | \n",
" 2018-01-01 | \n",
" 100000 | \n",
" 남자 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" 고객명 날짜 데이터_x 데이터_y\n",
"0 춘향 2018-01-01 20000 여자\n",
"1 춘향 2018-01-02 30000 여자\n",
"2 몽룡 2018-01-01 100000 남자"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"pd.merge(df1, df2, on='고객명')"
]
},
{
"cell_type": "markdown",
"metadata": {
"school_cell_uuid": "505311f5babf4ffba7b4978fedf21a64"
},
"source": [
"이 때 기준 열이 아니면서 이름이 같은 열에는 `_x` 또는 `_y` 와 같은 접미사가 붙는다."
]
},
{
"cell_type": "markdown",
"metadata": {
"school_cell_uuid": "a301562c92ae470db09c6f031fbf847b"
},
"source": [
"반대로 키가 되는 기준열의 이름이 두 데이터프레임에서 다르다면 `left_on`, `right_on` 인수를 사용하여 기준열을 명시해야 한다."
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {
"school_cell_uuid": "7f99a2c7a1594659b4fa08dec518aaf2"
},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" 이름 | \n",
" 성적 | \n",
"
\n",
" \n",
" \n",
" \n",
" 0 | \n",
" 영희 | \n",
" 1 | \n",
"
\n",
" \n",
" 1 | \n",
" 철수 | \n",
" 2 | \n",
"
\n",
" \n",
" 2 | \n",
" 철수 | \n",
" 3 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" 이름 성적\n",
"0 영희 1\n",
"1 철수 2\n",
"2 철수 3"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df1 = pd.DataFrame({\n",
" '이름': ['영희', '철수', '철수'],\n",
" '성적': [1, 2, 3]})\n",
"df1"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {
"school_cell_uuid": "ff87cec64cbe4948b9f8c278b5510db0"
},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" 성명 | \n",
" 성적2 | \n",
"
\n",
" \n",
" \n",
" \n",
" 0 | \n",
" 영희 | \n",
" 4 | \n",
"
\n",
" \n",
" 1 | \n",
" 영희 | \n",
" 5 | \n",
"
\n",
" \n",
" 2 | \n",
" 철수 | \n",
" 6 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" 성명 성적2\n",
"0 영희 4\n",
"1 영희 5\n",
"2 철수 6"
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df2 = pd.DataFrame({\n",
" '성명': ['영희', '영희', '철수'],\n",
" '성적2': [4, 5, 6]})\n",
"df2"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {
"school_cell_uuid": "84194614f5064491a3563b2044ce77c9"
},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" 이름 | \n",
" 성적 | \n",
" 성명 | \n",
" 성적2 | \n",
"
\n",
" \n",
" \n",
" \n",
" 0 | \n",
" 영희 | \n",
" 1 | \n",
" 영희 | \n",
" 4 | \n",
"
\n",
" \n",
" 1 | \n",
" 영희 | \n",
" 1 | \n",
" 영희 | \n",
" 5 | \n",
"
\n",
" \n",
" 2 | \n",
" 철수 | \n",
" 2 | \n",
" 철수 | \n",
" 6 | \n",
"
\n",
" \n",
" 3 | \n",
" 철수 | \n",
" 3 | \n",
" 철수 | \n",
" 6 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" 이름 성적 성명 성적2\n",
"0 영희 1 영희 4\n",
"1 영희 1 영희 5\n",
"2 철수 2 철수 6\n",
"3 철수 3 철수 6"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"pd.merge(df1, df2, left_on='이름', right_on=\"성명\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"school_cell_uuid": "1c7adc88d10c45a2b72d549a04164e80"
},
"source": [
"일반 데이터 열이 아닌 인덱스를 기준열로 사용하려면 `left_index` 또는 `right_index` 인수를 `True` 로 설정한다."
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {
"school_cell_uuid": "ab41a24dc50e4c3fac5150a1d0f82b6d"
},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" 도시 | \n",
" 연도 | \n",
" 인구 | \n",
"
\n",
" \n",
" \n",
" \n",
" 0 | \n",
" 서울 | \n",
" 2000 | \n",
" 9853972 | \n",
"
\n",
" \n",
" 1 | \n",
" 서울 | \n",
" 2005 | \n",
" 9762546 | \n",
"
\n",
" \n",
" 2 | \n",
" 서울 | \n",
" 2010 | \n",
" 9631482 | \n",
"
\n",
" \n",
" 3 | \n",
" 부산 | \n",
" 2000 | \n",
" 3655437 | \n",
"
\n",
" \n",
" 4 | \n",
" 부산 | \n",
" 2005 | \n",
" 3512547 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" 도시 연도 인구\n",
"0 서울 2000 9853972\n",
"1 서울 2005 9762546\n",
"2 서울 2010 9631482\n",
"3 부산 2000 3655437\n",
"4 부산 2005 3512547"
]
},
"execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df1 = pd.DataFrame({\n",
" '도시': ['서울', '서울', '서울', '부산', '부산'],\n",
" '연도': [2000, 2005, 2010, 2000, 2005],\n",
" '인구': [9853972, 9762546, 9631482, 3655437, 3512547]})\n",
"df1"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {
"school_cell_uuid": "03c8c1c3b9b24dff90ae26c4064f9d2e"
},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" | \n",
" 데이터1 | \n",
" 데이터2 | \n",
"
\n",
" \n",
" \n",
" \n",
" 부산 | \n",
" 2000 | \n",
" 0 | \n",
" 1 | \n",
"
\n",
" \n",
" 2005 | \n",
" 2 | \n",
" 3 | \n",
"
\n",
" \n",
" 서울 | \n",
" 2000 | \n",
" 4 | \n",
" 5 | \n",
"
\n",
" \n",
" 2005 | \n",
" 6 | \n",
" 7 | \n",
"
\n",
" \n",
" 2010 | \n",
" 8 | \n",
" 9 | \n",
"
\n",
" \n",
" 2015 | \n",
" 10 | \n",
" 11 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" 데이터1 데이터2\n",
"부산 2000 0 1\n",
" 2005 2 3\n",
"서울 2000 4 5\n",
" 2005 6 7\n",
" 2010 8 9\n",
" 2015 10 11"
]
},
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df2 = pd.DataFrame(\n",
" np.arange(12).reshape((6, 2)),\n",
" index=[['부산', '부산', '서울', '서울', '서울', '서울'],\n",
" [2000, 2005, 2000, 2005, 2010, 2015]],\n",
" columns=['데이터1', '데이터2'])\n",
"df2"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {
"school_cell_uuid": "25ed02de1b984b9bafdd450b6f391112"
},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" 도시 | \n",
" 연도 | \n",
" 인구 | \n",
" 데이터1 | \n",
" 데이터2 | \n",
"
\n",
" \n",
" \n",
" \n",
" 0 | \n",
" 서울 | \n",
" 2000 | \n",
" 9853972 | \n",
" 4 | \n",
" 5 | \n",
"
\n",
" \n",
" 1 | \n",
" 서울 | \n",
" 2005 | \n",
" 9762546 | \n",
" 6 | \n",
" 7 | \n",
"
\n",
" \n",
" 2 | \n",
" 서울 | \n",
" 2010 | \n",
" 9631482 | \n",
" 8 | \n",
" 9 | \n",
"
\n",
" \n",
" 3 | \n",
" 부산 | \n",
" 2000 | \n",
" 3655437 | \n",
" 0 | \n",
" 1 | \n",
"
\n",
" \n",
" 4 | \n",
" 부산 | \n",
" 2005 | \n",
" 3512547 | \n",
" 2 | \n",
" 3 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" 도시 연도 인구 데이터1 데이터2\n",
"0 서울 2000 9853972 4 5\n",
"1 서울 2005 9762546 6 7\n",
"2 서울 2010 9631482 8 9\n",
"3 부산 2000 3655437 0 1\n",
"4 부산 2005 3512547 2 3"
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"pd.merge(df1, df2, left_on=['도시', '연도'], right_index=True)"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {
"school_cell_uuid": "404694ddf9a04fe0885d1811cb803b70"
},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" 서울 | \n",
" 부산 | \n",
"
\n",
" \n",
" \n",
" \n",
" a | \n",
" 1.0 | \n",
" 2.0 | \n",
"
\n",
" \n",
" c | \n",
" 3.0 | \n",
" 4.0 | \n",
"
\n",
" \n",
" e | \n",
" 5.0 | \n",
" 6.0 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" 서울 부산\n",
"a 1.0 2.0\n",
"c 3.0 4.0\n",
"e 5.0 6.0"
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df1 = pd.DataFrame(\n",
" [[1., 2.], [3., 4.], [5., 6.]],\n",
" index=['a', 'c', 'e'],\n",
" columns=['서울', '부산'])\n",
"df1"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {
"school_cell_uuid": "1b12fad0ec414408838c464cd706e5d3"
},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" 대구 | \n",
" 광주 | \n",
"
\n",
" \n",
" \n",
" \n",
" b | \n",
" 7.0 | \n",
" 8.0 | \n",
"
\n",
" \n",
" c | \n",
" 9.0 | \n",
" 10.0 | \n",
"
\n",
" \n",
" d | \n",
" 11.0 | \n",
" 12.0 | \n",
"
\n",
" \n",
" e | \n",
" 13.0 | \n",
" 14.0 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" 대구 광주\n",
"b 7.0 8.0\n",
"c 9.0 10.0\n",
"d 11.0 12.0\n",
"e 13.0 14.0"
]
},
"execution_count": 20,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df2 = pd.DataFrame(\n",
" [[7., 8.], [9., 10.], [11., 12.], [13, 14]],\n",
" index=['b', 'c', 'd', 'e'],\n",
" columns=['대구', '광주'])\n",
"df2"
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {
"school_cell_uuid": "b046e6a685374379a755253cc164d7cd"
},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" 서울 | \n",
" 부산 | \n",
" 대구 | \n",
" 광주 | \n",
"
\n",
" \n",
" \n",
" \n",
" a | \n",
" 1.0 | \n",
" 2.0 | \n",
" NaN | \n",
" NaN | \n",
"
\n",
" \n",
" b | \n",
" NaN | \n",
" NaN | \n",
" 7.0 | \n",
" 8.0 | \n",
"
\n",
" \n",
" c | \n",
" 3.0 | \n",
" 4.0 | \n",
" 9.0 | \n",
" 10.0 | \n",
"
\n",
" \n",
" d | \n",
" NaN | \n",
" NaN | \n",
" 11.0 | \n",
" 12.0 | \n",
"
\n",
" \n",
" e | \n",
" 5.0 | \n",
" 6.0 | \n",
" 13.0 | \n",
" 14.0 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" 서울 부산 대구 광주\n",
"a 1.0 2.0 NaN NaN\n",
"b NaN NaN 7.0 8.0\n",
"c 3.0 4.0 9.0 10.0\n",
"d NaN NaN 11.0 12.0\n",
"e 5.0 6.0 13.0 14.0"
]
},
"execution_count": 21,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"pd.merge(df1, df2, how='outer', left_index=True, right_index=True)"
]
},
{
"cell_type": "markdown",
"metadata": {
"school_cell_uuid": "287c4da943664246bbdebaa20660bfa1"
},
"source": [
"### join 메서드"
]
},
{
"cell_type": "markdown",
"metadata": {
"school_cell_uuid": "df6683db4e0b45e6a3a974ea5049bb9c"
},
"source": [
"`merge` 명령어 대신 `join` 메서드를 사용할 수도 있다."
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {
"school_cell_uuid": "c3b619ed36a34dd882fa95d6da27d8f8"
},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" 서울 | \n",
" 부산 | \n",
" 대구 | \n",
" 광주 | \n",
"
\n",
" \n",
" \n",
" \n",
" a | \n",
" 1.0 | \n",
" 2.0 | \n",
" NaN | \n",
" NaN | \n",
"
\n",
" \n",
" b | \n",
" NaN | \n",
" NaN | \n",
" 7.0 | \n",
" 8.0 | \n",
"
\n",
" \n",
" c | \n",
" 3.0 | \n",
" 4.0 | \n",
" 9.0 | \n",
" 10.0 | \n",
"
\n",
" \n",
" d | \n",
" NaN | \n",
" NaN | \n",
" 11.0 | \n",
" 12.0 | \n",
"
\n",
" \n",
" e | \n",
" 5.0 | \n",
" 6.0 | \n",
" 13.0 | \n",
" 14.0 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" 서울 부산 대구 광주\n",
"a 1.0 2.0 NaN NaN\n",
"b NaN NaN 7.0 8.0\n",
"c 3.0 4.0 9.0 10.0\n",
"d NaN NaN 11.0 12.0\n",
"e 5.0 6.0 13.0 14.0"
]
},
"execution_count": 22,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df1.join(df2, how='outer')"
]
},
{
"cell_type": "markdown",
"metadata": {
"bootstrap": {
"panel": {
"class": "panel-default"
}
},
"school_cell_uuid": "dcc917f76597477e9aa16846fb9f36bc"
},
"source": [
"````{admonition} 연습 문제 4.6.1\n",
"\n",
"두 개의 데이터프레임을 만들고 merge 명령으로 합친다. 단 데이터프레임은 다음 조건을 만족해야 한다.\n",
"\n",
"1. 각각 5 x 5 이상의 크기를 가진다.\n",
"2. 공통 열을 하나 이상 가진다. 다만 공통 열의 이름은 서로 다르다.\n",
"````"
]
},
{
"cell_type": "markdown",
"metadata": {
"school_cell_uuid": "a5df58b4b7a54c04baaa13015929fdad"
},
"source": [
"## `concat` 함수를 사용한 데이터 연결"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"```{margin}\n",
"`concat`\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {
"school_cell_uuid": "ece1c7a551c1450392fe9566465542b5"
},
"source": [
"`concat` 함수를 사용하면 기준 열(key column)을 사용하지 않고 단순히 데이터를 연결(concatenate)한다.\n",
"\n",
"기본적으로는 위/아래로 데이터 행을 연결한다. 단순히 두 시리즈나 데이터프레임을 연결하기 때문에 인덱스 값이 중복될 수 있다. "
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {
"school_cell_uuid": "9728e65012484a409c1b5654cf67871f"
},
"outputs": [],
"source": [
"s1 = pd.Series([0, 1], index=['A', 'B'])\n",
"s2 = pd.Series([2, 3, 4], index=['A', 'B', 'C'])"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {
"school_cell_uuid": "eee3eb61c0774de088feecc6583846e3"
},
"outputs": [
{
"data": {
"text/plain": [
"A 0\n",
"B 1\n",
"dtype: int64"
]
},
"execution_count": 24,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"s1"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {
"school_cell_uuid": "8fc57c638a6440ad955b7c9fab302725"
},
"outputs": [
{
"data": {
"text/plain": [
"A 2\n",
"B 3\n",
"C 4\n",
"dtype: int64"
]
},
"execution_count": 25,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"s2"
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {
"school_cell_uuid": "3fc8856b6d5740f9a80b57c0a171c323"
},
"outputs": [
{
"data": {
"text/plain": [
"A 0\n",
"B 1\n",
"A 2\n",
"B 3\n",
"C 4\n",
"dtype: int64"
]
},
"execution_count": 26,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"pd.concat([s1, s2])"
]
},
{
"cell_type": "markdown",
"metadata": {
"school_cell_uuid": "51015eb5b8cc4b0887f1b950b14e79eb"
},
"source": [
"만약 옆으로 데이터 열을 연결하고 싶으면 `axis=1`로 인수를 설정한다."
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {
"school_cell_uuid": "33473e4aeba0432abe750caf376d93e2"
},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" 데이터1 | \n",
" 데이터2 | \n",
"
\n",
" \n",
" \n",
" \n",
" a | \n",
" 0 | \n",
" 1 | \n",
"
\n",
" \n",
" b | \n",
" 2 | \n",
" 3 | \n",
"
\n",
" \n",
" c | \n",
" 4 | \n",
" 5 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" 데이터1 데이터2\n",
"a 0 1\n",
"b 2 3\n",
"c 4 5"
]
},
"execution_count": 27,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df1 = pd.DataFrame(\n",
" np.arange(6).reshape(3, 2),\n",
" index=['a', 'b', 'c'],\n",
" columns=['데이터1', '데이터2'])\n",
"df1"
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {
"school_cell_uuid": "eedb9d4110ac4cb99341b851d61d8605"
},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" 데이터3 | \n",
" 데이터4 | \n",
"
\n",
" \n",
" \n",
" \n",
" a | \n",
" 5 | \n",
" 6 | \n",
"
\n",
" \n",
" c | \n",
" 7 | \n",
" 8 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" 데이터3 데이터4\n",
"a 5 6\n",
"c 7 8"
]
},
"execution_count": 28,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df2 = pd.DataFrame(\n",
" 5 + np.arange(4).reshape(2, 2),\n",
" index=['a', 'c'],\n",
" columns=['데이터3', '데이터4'])\n",
"df2"
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {
"school_cell_uuid": "43614010ef0349a5aae59792d3bb9ca2"
},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" 데이터1 | \n",
" 데이터2 | \n",
" 데이터3 | \n",
" 데이터4 | \n",
"
\n",
" \n",
" \n",
" \n",
" a | \n",
" 0 | \n",
" 1 | \n",
" 5.0 | \n",
" 6.0 | \n",
"
\n",
" \n",
" b | \n",
" 2 | \n",
" 3 | \n",
" NaN | \n",
" NaN | \n",
"
\n",
" \n",
" c | \n",
" 4 | \n",
" 5 | \n",
" 7.0 | \n",
" 8.0 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" 데이터1 데이터2 데이터3 데이터4\n",
"a 0 1 5.0 6.0\n",
"b 2 3 NaN NaN\n",
"c 4 5 7.0 8.0"
]
},
"execution_count": 29,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"pd.concat([df1, df2], axis=1)"
]
},
{
"cell_type": "markdown",
"metadata": {
"bootstrap": {
"panel": {
"class": "panel-default"
}
},
"school_cell_uuid": "6383f37855f34c88a09ee88f6ea76f75"
},
"source": [
"````{admonition} 연습 문제 2\n",
"\n",
"어느 회사의 전반기(1월 ~ 6월) 실적을 나타내는 데이터프레임과 후반기(7월 ~ 12월) 실적을 나타내는 데이터프레임을 만든 뒤 합친다.\n",
"실적 정보는 \"매출\", \"비용\", \"이익\" 으로 이루어진다. (이익 = 매출 - 비용).\n",
"\n",
"또한 1년간의 총 실적을 마지막 행으로 덧붙인다.\n",
"````"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"celltoolbar": "Edit Metadata",
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.6"
},
"latex_envs": {
"LaTeX_envs_menu_present": true,
"autoclose": false,
"autocomplete": true,
"bibliofile": "biblio.bib",
"cite_by": "apalike",
"current_citInitial": 1,
"eqLabelWithNumbers": true,
"eqNumInitial": 1,
"hotkeys": {
"equation": "Ctrl-E",
"itemize": "Ctrl-I"
},
"labels_anchors": false,
"latex_user_defs": false,
"report_style_numbering": false,
"user_envs_cfg": false
}
},
"nbformat": 4,
"nbformat_minor": 4
}